#####################################################################################
#
# google_searches.pl
#   Extracts parameters from Google search URLs
#
# Plugin Author: Ryan Benson (ryan@obsidianforensics.com)
#
#####################################################################################


package google_searches;
use strict;
use URI::Escape;

my %config = (friendlyName   => "Google Searches",
              description    => "Extracts parameters from Google search URLs",
              artifactType   => "url",
              remoteLookups  => 0,
              browser        => "all",
              browserVersion => 19,
              version        => 20120928);

sub getConfig       { return %config; }
sub getFriendlyName { return $config{friendlyName}; }
sub getDescription  { return $config{description};; }
sub getArtifactType { return $config{artifactType}; }
sub getRemoteLookups{ return $config{remoteLookups}; }
sub getVersion      { return $config{version}; }

sub pluginmain{

    my $select_h = $::datastore->prepare("  SELECT rid,url,derived 
                                            FROM urls 
                                            WHERE url LIKE '%google.com%'  ");

    my $update_h = $::datastore->prepare(" UPDATE urls SET derived=? WHERE rid=? ");

    $select_h->execute();

    my %time_abbr = ("s", "second", "n", "minute", "h", "hour", "d", "day", "w", "week", "m", "month", "y", "year");
    my $counter = 0;
    while (my @row = $select_h->fetchrow) {
        my $derived;
        
        my $raw_search = $row[1];
        my $search;
        
        if ($raw_search =~ m|^http(s)?://www\.google\.com/search\?|){
            $search = $raw_search;
            $search =~ s|^http(s)?://www\.google\.com/search\?||;
        }
        
        if ($raw_search =~ m|^http(s)?://www\.google\.com/#q=|){
            $search = $raw_search;
            $search =~ s!^http(s)?://www\.google\.com/#q=!q=!;
        }
        
        my %parameters;
        
        if ($search){    
            $search =~ s|#q=|&#q=|;               # Add a & before #q parameter so it will split correctly
            my @parameters = split /&/, $search;  # Split the search query on the '&' delimiter
            foreach my $parameter (@parameters){
                $parameter =~ /(.+?)=(.+)/;       # and then split each parameter on the first '='
                $parameters{$1} = $2;  }          # and stick the parameter name and value in hash
        
            if ($parameters{'q'}){  # 'q' parameter must be present for rest of parameters to be parsed
                $parameters{'q'} =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;  # Replace % encoded URIs
                $parameters{'q'} =~ s/\+/ /g;                             # Replace + with space
                $derived = "Searched for \"$parameters{'q'}\"  ["; 
                $counter++;
     
				if ($parameters{'pws'} eq '0' ){
					$derived .= "Google personalization turned off | ";  }

				if ($parameters{'num'}){
					$derived .= "showing $parameters{num} results per page | ";  }

				if ($parameters{'filter'} eq '0' ){
					$derived .= "Omitted/Similar results filter disabled | ";  }

				if ($parameters{'btnl'}==1 ){
					$derived .= "'I'm Feeling Lucky' search | ";  }
					
				if ($parameters{'safe'}){
					$derived .= "SafeSearch: $parameters{'safe'} | ";  }

				if ( $parameters{'as_qdr'} =~ /(s|n|h|d|w|m|y)(\d{0,9})/ ){
						if ($1 && $2) {
							$derived .= "Results in the past $2 $time_abbr{$1}s | ";  }
						elsif ($1) {
							$derived .= "Results in the past $time_abbr{$1} | ";  }  }                
					
				if ($parameters{'tbs'}){
					if ( $parameters{'tbs'} =~ /qdr:(s|n|h|d|w|m|y)(\d{0,9})/ ){
						if ($1 && $2) {
							$derived .= "Results in the past $2 $time_abbr{$1}s | ";  }
						elsif ($1) {
							$derived .= "Results in the past $time_abbr{$1} | ";  }  }
					if ( $parameters{'tbs'} =~ /^cdr/ ){
						$parameters{'tbs'} =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;  # Replace % encoded URIs
						if ( $parameters{'tbs'} =~ m|cd_min:(\d{1,2}/\d{1,2}/\d{2,4}),cd_max:(\d{1,2}/\d{1,2}/\d{2,4})| ){
							$derived .= "Results in custom range $1 - $2 | ";  }  }  }
					if ( $parameters{'tbs'} =~ /^dfn:1/ ){
						$derived .= "Dictionary definition | ";  }
					if ( $parameters{'tbs'} =~ /^img:1/ ){
						$derived .= "Sites with images | ";  }
					if ( $parameters{'tbs'} =~ /^clir:1/ ){
						$derived .= "Translated sites | ";  }
					if ( $parameters{'tbs'} =~ /^li:1/ ){
						$derived .= "Verbatim results | ";  }
					if ( $parameters{'tbs'} =~ /^vid:1/ ){
						$derived .= "Video results | ";  }
					if ( $parameters{'tbs'} =~ /^nws:1/ ){
						$derived .= "News results | ";  }
					if ( $parameters{'tbs'} =~ /sbd:1/ ){
						$derived .= "Sorted by date | ";  }
						
				if ($parameters{'bih'} && $parameters{'biw'}){
					$derived .= "Browser Screen $parameters{'biw'}x$parameters{'bih'} | ";  }

				if ($parameters{'pq'}){
					$parameters{'pq'} =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;  # Replace % encoded URIs
					$parameters{'pq'} =~ s/\+/ /g;                             # Replace + with space
					if ($parameters{'pq'} ne $parameters{'q'}){                # Don't include PQ if same as Q to save space
						$derived .= "Previous Query: \"$parameters{'pq'}\" | ";  }  }

				if ($parameters{'oq'}){
					$parameters{'oq'} =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;  # Replace % encoded URIs
					$parameters{'oq'} =~ s/\+/ /g;                             # Replace + with space
					if ($parameters{'oq'} ne $parameters{'q'}){                # Don't include OQ if same as Q to save space
						$derived .= "Original Query: \"$parameters{'oq'}\" | ";  }  }

				if ($parameters{'as_sitesearch'}){
					$derived .= "Search only $parameters{'as_sitesearch'} | ";  }
					
				if ($parameters{'as_filetype'}){
					$derived .= "Only show $parameters{'as_filetype'} files | ";  }

				if ($parameters{'sourceid'}){                
					$derived .= "Using $parameters{sourceid} | ";  }
					
				if ( $derived =~ /\[$/ ) { chop($derived); }  # removed [ if no other parameters
				else { chop($derived); chop($derived); chop($derived);  $derived .= "]"; } # else removed last 3 chars and add ]
			}
        }
        
        $update_h->execute( $derived, $row[0] );
    }
    ::printStatus("$counter searches parsed");
}

1;